#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <pthread.h>
using namespace std;

#include "Mythread.hpp"
#include "SmartMutex.hpp"
#include "Log.hpp"

class ThreadData
{
public:
    ThreadData(string name) : _threadname(name)
    {
    }

    string _threadname;
};

template <class T>
class ThreadPool
{
private:
    static const int default_thread_num;

    void ThreadWait(ThreadData &td)
    {
        LOG(Debug, "线程%s等待\n", CSTR(td._threadname));
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThreadWake()
    {
        pthread_cond_signal(&_cond);
    }

public:
    ThreadPool(size_t thread_num = default_thread_num) : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        for (int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread-" + to_string(i + 1);
            ThreadData td(threadname);
            LOG(Debug, "线程%s已经创建好了\n", CSTR(threadname));

            _threads.emplace_back(threadname, bind(&ThreadPool<T>::ThreadRun, this, td), td);
        }
    }

    void Start()
    {
        for(auto& thread : _threads)
        {
            LOG(Debug, "线程启动\n");
            thread.Start();
        }
    }

    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            T t;
            // 取任务
            {
                SmartMutex smartmutex(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                }

                t = _q.front();
                _q.pop();
                LOG(Info, "线程%s取到任务：%s\n", CSTR(td._threadname), CSTR(t()));
            }

            // 执行任务
            LOG(Info, "线程%s执行任务：%s\n", CSTR(td._threadname), CSTR(t()));
            t();
        }
    }

    void Push(T &in)
    {
        SmartMutex smartmutex(&_mutex);
        _q.push(in);
        LOG(Info, "主线程插入任务：%s\n", CSTR(in()));
        ThreadWake();
    }

    void Destroy()
    {
        for(auto& thread : _threads)
        {
            LOG(Info, "线程销毁\n");
            thread.Join();
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }



private:
    queue<T> _q;
    vector<Thread<ThreadData>> _threads;
    size_t _thread_num;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};

template <class T>
const int ThreadPool<T>::default_thread_num = 5;
